package com.ormbench.hibernate;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;

/**
 * Basic Hibernate helper class, handles SessionFactory, Session and
 * Transaction.
 */
public class HibernateUtil {
	private static final ThreadLocal<Boolean> rollbackOnly = new ThreadLocal<Boolean>();
	private static SessionFactory sessionFactory;

	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public static void setSessionFactory(SessionFactory factory) {
		sessionFactory = factory;
	}

	/**
	 * Retrieves the current Session
	 * 
	 * @return Session
	 */
	public static Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	/**
	 * Retrieves the new Session
	 * 
	 * @return Session
	 */
	public static Session newSession() {
		return sessionFactory.openSession();
	}

	/**
	 * Start a new database transaction.
	 */
	public static void beginTransaction() {
		getSession().beginTransaction();
		rollbackOnly.set(Boolean.FALSE);
	}
	
	/**
	 * Used by resolve transaction to know to rollback
	 */
	public static void rollbackOnly() {
		rollbackOnly.set(Boolean.TRUE);
	}
	
	/**
	 * resolves transaction
	 */
	public static void resolveTransaction() {
		if (rollbackOnly.get()) {
			rollbackTransaction();
		} else {
			commitTransaction();
		}
	}

	/**
	 * Commit the database transaction.
	 */
	public static void commitTransaction() {
		Transaction transaction = getSession().getTransaction();
		try {
			if ((transaction != null) && transaction.isActive()) {
				transaction.commit();
			}
		} catch (HibernateException e) {
			rollbackTransaction();
			throw e;
		}
	}

	/**
	 * Rollback the database transaction.
	 */
	public static void rollbackTransaction() {
		Transaction transaction = getSession().getTransaction();
		if ((transaction != null) && transaction.isActive())
		{
			transaction.rollback();
		}
	}

	/**
	 * Returns the projection for a given class
	 * 
	 * @param c
	 * @return
	 */
	public static Projection getProjection(Class<?> c) {
		String[] properties = sessionFactory.getClassMetadata(c).getPropertyNames();
		ProjectionList list = Projections.projectionList();
		for (int i = 0; i < properties.length; ++i) {
			list.add(Projections.property(properties[i]), properties[i]);
		}
		return list;
	}
}
